#include <windows.h>
#include "PCB_Board.h"


namespace washer{

	PCB_Board* PCB_Board::pcb_instance = 0;


	PCB_Board* PCB_Board::Instance(Door* d, Motor* m, Pump* p, Soap_Tray* st, Tub* t, Valve* v_hot, Valve* v_cold, Menu* menu)
	{
		if (!pcb_instance)
		{
			pcb_instance = new PCB_Board(d, m, p, st, t, v_hot, v_cold, menu);

		}
		return pcb_instance;
	}
	
	PCB_Board::PCB_Board(Door* door, Motor* motor, Pump* pump, Soap_Tray* soap_tray, Tub* tub, Valve* valve_hot, Valve* valve_cold, Menu* menu)
	{
		try
		{
			
			d = door;
			d = new Door();
			m = motor;
			m = new Motor();
			p = pump;
			p = new Pump();
			st = soap_tray;
			st = new Soap_Tray();
			t = tub;
			t = new Tub();
			v_hot = valve_hot;
			v_hot = new Valve();
			v_cold = valve_cold;
			v_cold = new Valve();
			mu = menu;
			
			
		}
		catch (std::bad_alloc&)
		{
			std::cerr << "Error allocating memory for washing machine." << std::endl;
		}
	}


	PCB_Board::~PCB_Board(void)
	{
		
		delete d;
		delete m;
		delete p;
		delete st;
		delete t;
		delete v_cold;
		delete v_hot;
		delete mu;
		
	}
		
	void PCB_Board::main_loop()
	{
		bool loop = true;

		while (loop)
		{
			mu->display_message("Please enter a number for cycle:\n1.Wash\n2.Rinse Only\n3.Spin and Drain\n4.Exit");
			int selection = mu->receive_input();
			switch (selection)
			{
			case 1:
				{
					mu->display_message("You have selected the wash cycle.");
					wash();
					break;
				}
			case 2:
				{
					mu->display_message("You have selected the rinse cycle.");
					rinse();
					break;
				}
			case 3:
				{
					mu->display_message("You have selected the spin cycle.");
					spin();
					break;
				}
			case 4: loop = false;
				break;
			default: mu->display_message("Invalid selection, please try again.");
				break;

			}
		}
	}

	void PCB_Board::wash()
	{
		//Lock door
		mu->display_message("Locking door");
		d->d_lock();
		Sleep(2000);

		//Fill tub with water
		fill_tub();
		
		//Fill tub with soap
		st->dispense();
		mu->display_message("Dispensing soap...");
		Sleep(5000);

		//Agitate
		m->agitate_tub();
		mu->display_message("Agitating tub...");
		Sleep(5000);

		//Drain
		drain();

		mu->display_message("Now entering the rinse cycle.");
		rinse();
	}

	void PCB_Board::rinse()
	{
		//Fill tub with water
		fill_tub();

		//Agitate
		m->agitate_tub();
		mu->display_message("Agitating tub...");
		Sleep(5000);

		//Drain
		drain();
		
		mu->display_message("Now entering the spin cycle.");
		spin();
	}

	void PCB_Board::spin()
	{
		//High Speed Spin
		m->spin_tub();
		mu->display_message("Spinning tub...");
		Sleep(5000);

		//Drain
		drain();

		//Unlock
		bool safety = d->d_unlock();
		mu->display_message("Door unlocked, clothes are clean.");
	}

	void PCB_Board::drain()
	{
		p->drain_water();
		mu->display_message("Draining water...\n");
		Sleep(5000);
	}

	void PCB_Board::fill_tub()
	{
		v_hot->v_open();
		v_cold->v_open();
		mu->display_message("Filling tub with water...");
		Sleep(2000);
		mu->display_message("...");
		Sleep(2000);
		mu->display_message("...");
		Sleep(2000);
		v_hot->v_close();
		v_cold->v_close();
		mu->display_message("\nClosing valves.");

	}
			
	double PCB_Board::sense_water()
	{
		return 0.0;
	}

	double PCB_Board::get_timeleft() const
	{
		return time_left;
	}

	bool PCB_Board::power_motor(Motor& m, bool power_on, double amps)
	{
		return false;
	}

	bool PCB_Board::power_pump(Pump& p, bool power_on)
	{
		return false;
	}

	bool PCB_Board::lock_door(Door& d, bool lock)
	{
		return false;
	}

	bool PCB_Board::dispense_soap(Soap_Tray& st, bool dispense)
	{
		return false;
	}

	void PCB_Board::selection(enum user_select){}

	void PCB_Board::display_error(){}

	
	PCB_Board::PCB_Board(const PCB_Board& new_board)
	{
		
		time_left = new_board.get_timeleft();
		serial_number = new_board.serial_number;
		
		d = new_board.d;
		m = new_board.m;
		p = new_board.p;
		st = new_board.st;
		t = new_board.t;
		v_hot = new_board.v_hot;
		v_cold = new_board.v_cold;
		mu = new_board.mu;
		

	}
	
	PCB_Board& PCB_Board::operator=(const PCB_Board& pcb)
	{
		if (this != &pcb)
		{
			time_left = pcb.time_left;
			serial_number = pcb.serial_number;
			d = pcb.d;
			m = pcb.m;
			st = pcb.st;
			t = pcb.t;
			v_hot = pcb.v_hot;
			v_cold = pcb.v_cold;
			mu = pcb.mu;
		}
		return *this;
	}
	
}